class Line:
    def __init__(self, x0, y0, x1, y1):
        self.x0 = x0
        self.y0 = y0
        self.x1 = x1
        self.y1 = y1
        self.dx = x1 - x0
        self.dy = y1 - y0
    
    def get_AABB(self):
        if self.dx > 0:
            x0 = self.x0
            x1 = self.x1
        else:
            x0 = self.x1
            x1 = self.x0
        if self.dy > 0:
            y0 = self.y0
            y1 = self.y1
        else:
            y0 = self.y1
            y1 = self.y0
        return x0, y0, x1, y1
    
    def hash(self, sector_w, sector_h):
        """WUT NO"""
        sectors = set()
        x0, y0, x1, y1 = self.get_AABB()
        for x in range(x0 // sector_w, x1 // sector_w):
            for y in range(y0 // sector_h, y1 // sector_h):
                sectors[(x0 + x, y0 + y)] = geom
    
    def hash_optimal(self, sector_w, sector_h):
        """Slower to execute, but should be worth it at runtime."""
        sectors = set()
        x0, y0, x1, y1 = self.get_AABB()
        subsegments = (x1 - x0) / sector_w / 2 + (y1 - y0) / sector_h / 2
        for i in range(subsegments):
            x0b = x0 + self.dx / subsegments * i
            x1b = x0 + self.dx / subsegments * (i + 1)
            y0b = y0 + self.dy / subsegments * i
            y1b = y0 + self.dy / subsegments * (i + 1)
            for x in range(x0b // sector_w, x1b // sector_w):
                for y in range(y0b // sector_h, y1b // sector_h):
                    sectors.add((x, y))
        return sectors
    
    def collide_line(self, x0, y0, x1, y1):
        t = (x1 - x0) * (self.y0 - y0) - (y1 - y0) * (self.x0 - x0) / \
            (y1 - y0) * (self.x1 - self.x0) - (x1 - x0) * (self.y1 - self.y0)
        return self.x0 + self.dx * t, self.y0 + self.dy * t, t

class Circle:
    def __init__(self, x, y, radius):
        self.x = x
        self.y = y
        self.radius = radius
    
    def get_AABB(self):
        return (self.x - self.radius, self.y - self.radius,
                self.x + self.radius, self.y + self.radius)

class Scene:
    """A class for storing objects and other data about a physics simulation.
    
    It keeps a set of static objects, and one of dynamic ones.
    It's divided in sectors(and has a size) to speed up collision detection.
    For simple purposes however, doing just Scene() is fine.
    """
    def __init__(self, sector_w=1, sector_h=1):
        """Makes the world.
        
        Ideally, sector_w and sector_h should be the size of the average
        object the simulation will handle
        """
        self.sector_w = sector_w
        self.sector_h = sector_h
        self.sectors = {}
        
        self.static_objects = set()
        self.dynamic_objects = set()
    
    def hash(self, geom):
        """Puts the static objects in the sectors they belong to"""
        x0, y0, x1, y1 = geom.get_AABB()
        for x in range(x0 // self.sector_w, x1 // self.sector_w):
            for y in range(y0 // self.sector_h, y1 // self.sector_h):
                self.sectors[(x0 + x, y0 + y)] = geom
    
    def hash_dynamic(self):
        for geom in self.dynamic_objects:
            pass
    
    def hash_all(self):
        self.sectors = {}
        for geom in self.static_objects:
            self.hash(geom)
        
        for geom in self.dynamic_objects:
            self.hash(geom)
    
    def candidates(self, x, y):
        """Candidates for collision at the given position
        
        This shouldn't actually be used.
        """
        x = x // self.sector_w
        y = y // self.sector_h
    
    def update(self, dt):
        pass

if __name__ == '__main__':
    s = Scene()
    l0 = Line(6, 9, 2, 2)
    l1 = Line(0, 0, 5, 5)
    l2 = Line(2, 0, 2, 10)
    s.static_objects.update((l0, l1, l2))
    s.hash_all()
    for k, v in s.sectors.items(): print k, v